package com.yonyou.brigade.order_center.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.enums.SqlLike;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.yonyou.brigade.basic_init.enums.ChannelEnum;
import com.yonyou.brigade.order_center.dao.BriTrainOrderMapper;
import com.yonyou.brigade.order_center.model.*;
import com.yonyou.brigade.order_center.service.*;
import com.yonyou.brigade.util.operateutil.DateUtils;
import com.yonyou.ybzboot.starter.common.util.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.*;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author jiangzhf@yonyou.com
 * @since 2018-06-14
 */
@Service
public class BriTrainOrderServiceImpl extends ServiceImpl<BriTrainOrderMapper, BriTrainOrder> implements IBriTrainOrderService {
    @Autowired
    private BriTrainOrderMapper briTrainOrderMapper;

    @Autowired
    @Qualifier("briTrainTicketServiceImpl")
    private IBriTrainTicketService briTrainTicketService;

    @Autowired
    private IBriTrainPaymentService briTrainPaymentService;

    @Autowired
    @Qualifier("briTrainPassengerServiceImpl")
    private IBriTrainPassengerService briTrainPassengerService;

    @Autowired
    private IInvoiceRelationshipService relationshipService;

    private static final Logger logger = LoggerFactory.getLogger(BriTrainOrderServiceImpl.class);


    @Override
    public List<BriTrainOrderDO> getBriTrainOrderDOs(Map params) {
        return briTrainOrderMapper.getBriTrainOrderDOs(params);
    }

    @Override
    public List<BriTrainOrder> getBriTrainOrder(Map params) {
        return briTrainOrderMapper.getBriTrainOrderList(params);
    }

    @Override
    public void updateIsBxStateByOrderIds(List<Integer> ids,int bxState)
    {
        Map params=new HashMap();
        params.put("ids",ids);
        params.put("bxState",bxState);
        briTrainOrderMapper.updateIsBxStateByOrderIds(params);
    }

    @Override
    public List<CnvTrainOrderDO> getCnvTrainOrderDos(Map<String, String> params, Date beginDate, Date endDate) {
        ArrayList<CnvTrainOrderDO> trainOrderDOs = new ArrayList<>();
        Wrapper<BriTrainOrder> wrapper = new EntityWrapper<>();
        for (Map.Entry<String, String> entry : params.entrySet()) {
            wrapper.eq(entry.getKey(), entry.getValue());
        }
        wrapper.ne(true,"is_note",1);
        wrapper.eq(true, "public_or_priveate", "1");
        wrapper.ne(true,"category","");
        wrapper.ne(true,"order_no","");
        List<BriTrainOrder> orderlist = briTrainOrderMapper.selectList(wrapper);
        ArrayList<String> orderTypeList = new ArrayList<String>(Arrays.asList("N","G","T"));
        ArrayList<String> orderStatusList = new ArrayList<String>(Arrays.asList("TP","GT","FR","GD"));
        if (orderlist != null && orderlist.size() > 0) {
            for(BriTrainOrder briTrainOrder : orderlist){
                // 过滤订单状态
                if (!StringUtils.isEmpty(briTrainOrder.getOrderType()) && orderTypeList.contains(briTrainOrder.getOrderType())
                        && !StringUtils.isEmpty(briTrainOrder.getOrderStatus()) && orderStatusList.contains(briTrainOrder.getOrderStatus())) {
                    CnvTrainOrderDO cnvTrainOrderDO = new CnvTrainOrderDO();
                    Wrapper<BriTrainTicket> ticketWrapper = new EntityWrapper<>();
                    ticketWrapper.groupBy("order_no");
                    ticketWrapper.having("order_no = {0}",briTrainOrder.getOrderNo());
                    List<BriTrainTicket> ticketList = briTrainTicketService.selectList(ticketWrapper);
                    if(ticketList.size() > 1){
                        BriTrainTicket briTrainTicketFrist ;
                        BriTrainTicket briTrainTicketSecond;
                        if(ticketList.get(0).getToDate() == null || ticketList.get(1).getToDate() == null
                                || ticketList.get(0).getToTime() == null || ticketList.get(1).getToTime() == null){
                            logger.info("订单号:"+ briTrainOrder.getOrderNo() +"msg:车票到达日期或时间为空");
                            continue;
                        }
                        if(ticketList.get(1).getToDate().after(ticketList.get(0).getToDate())
                                || ( ticketList.get(1).getToDate().equals(ticketList.get(0).getToDate())
                                && ticketList.get(1).getToTime().after(ticketList.get(0).getToTime()) ) ){
                            briTrainTicketFrist = ticketList.get(0);
                            briTrainTicketSecond = ticketList.get(1);
                        }else{
                            briTrainTicketFrist = ticketList.get(1);
                            briTrainTicketSecond = ticketList.get(0);
                        }

                        //过滤在开始日期之前的(已经结束)订单 和 在结束日期之后的(还未完成)订单
                        if(briTrainTicketSecond.getToDate().after(endDate) || briTrainTicketSecond.getToDate().before(beginDate)){
                            continue;
                        }
                        //去程信息
                        cnvTrainOrderDO.setTktPrice(briTrainTicketFrist.getTktPrice());
                        cnvTrainOrderDO.setTrainCode(briTrainTicketFrist.getTrainCode());
                        cnvTrainOrderDO.setTrainCodeName(briTrainTicketFrist.getTrainCodeName());
                        cnvTrainOrderDO.setFromStation(briTrainTicketFrist.getFromStation());
                        cnvTrainOrderDO.setToStation(briTrainTicketFrist.getToStation());
                        cnvTrainOrderDO.setTrainDate(briTrainTicketFrist.getTrainDate());
                        cnvTrainOrderDO.setFromTime(DateUtils.dateToTime(briTrainTicketFrist.getFromTime()));
                        cnvTrainOrderDO.setToDate(briTrainTicketFrist.getToDate());
                        cnvTrainOrderDO.setToTime(DateUtils.dateToTime(briTrainTicketFrist.getToTime()));
                        cnvTrainOrderDO.setSeatType(briTrainTicketFrist.getSeatType());
                        cnvTrainOrderDO.setTunTime(briTrainTicketFrist.getTunTime());
                        cnvTrainOrderDO.setTrainBox(briTrainTicketFrist.getTrainBox());
                        cnvTrainOrderDO.setSeatNo(briTrainTicketFrist.getSeatNo());
                        cnvTrainOrderDO.setCounterFee(briTrainTicketFrist.getCounterFee());

                        //返程信息
                        cnvTrainOrderDO.setTktPrice2(briTrainTicketSecond.getTktPrice());
                        cnvTrainOrderDO.setTrainCode2(briTrainTicketSecond.getTrainCode());
                        cnvTrainOrderDO.setTrainCodeName2(briTrainTicketSecond.getTrainCodeName());
                        cnvTrainOrderDO.setFromStation2(briTrainTicketSecond.getFromStation());
                        cnvTrainOrderDO.setToStation2(briTrainTicketSecond.getToStation());
                        cnvTrainOrderDO.setTrainDate2(briTrainTicketSecond.getTrainDate());
                        cnvTrainOrderDO.setFromTime2(DateUtils.dateToTime(briTrainTicketSecond.getFromTime()));
                        cnvTrainOrderDO.setToDate2(briTrainTicketSecond.getToDate());
                        cnvTrainOrderDO.setToTime2(DateUtils.dateToTime(briTrainTicketSecond.getToTime()));
                        cnvTrainOrderDO.setSeatType2(briTrainTicketSecond.getSeatType());
                        cnvTrainOrderDO.setTunTime2(briTrainTicketSecond.getTunTime());
                        cnvTrainOrderDO.setTrainBox2(briTrainTicketSecond.getTrainBox());
                        cnvTrainOrderDO.setSeatNo2(briTrainTicketSecond.getSeatNo());
                        cnvTrainOrderDO.setCounterFee2(briTrainTicketSecond.getCounterFee());
                    }else{
                        if( ticketList.size() == 0 || ticketList.get(0).getToDate() == null ){
                            logger.info("订单号:"+ briTrainOrder.getOrderNo() +"msg:车票到达日期或时间为空");
                            continue;
                        }
                        BriTrainTicket briTrainTicket = ticketList.get(0);
                        if( beginDate.after(briTrainTicket.getToDate()) || endDate.before(briTrainTicket.getTrainDate())){
                            continue;
                        }
                        cnvTrainOrderDO.setTktPrice(briTrainTicket.getTktPrice());
                        cnvTrainOrderDO.setTrainCode(briTrainTicket.getTrainCode());
                        cnvTrainOrderDO.setTrainCodeName(briTrainTicket.getTrainCodeName());
                        cnvTrainOrderDO.setFromStation(briTrainTicket.getFromStation());
                        cnvTrainOrderDO.setToStation(briTrainTicket.getToStation());
                        cnvTrainOrderDO.setTrainDate(briTrainTicket.getTrainDate());
                        cnvTrainOrderDO.setFromTime(DateUtils.dateToTime(briTrainTicket.getFromTime()));
                        cnvTrainOrderDO.setToDate(briTrainTicket.getToDate());
                        cnvTrainOrderDO.setToTime(DateUtils.dateToTime(briTrainTicket.getToTime()));
                        cnvTrainOrderDO.setSeatType(briTrainTicket.getSeatType());
                        cnvTrainOrderDO.setTunTime(briTrainTicket.getTunTime());
                        cnvTrainOrderDO.setTrainBox(briTrainTicket.getTrainBox());
                        cnvTrainOrderDO.setSeatNo(briTrainTicket.getSeatNo());
                        cnvTrainOrderDO.setCounterFee(briTrainTicket.getCounterFee());
                    }
                    convertFromBriTrainOrder(briTrainOrder, cnvTrainOrderDO);

                    //乘客姓名
                    Wrapper<BriTrainPassenger> passengerWrapper = new EntityWrapper<>();
                    passengerWrapper.eq("order_no",briTrainOrder.getOrderNo());
                    List<BriTrainPassenger> passengerList = briTrainPassengerService.selectList(passengerWrapper);
                    convertFromBriTrainPassengers(cnvTrainOrderDO, passengerList);
                    trainOrderDOs.add(cnvTrainOrderDO);
                }
            }
        }
        return trainOrderDOs;
    }

    private void convertFromBriTrainPassengers(CnvTrainOrderDO cnvTrainOrderDO, List<BriTrainPassenger> passengerList) {
        if (!CollectionUtils.isEmpty(passengerList)) {
            StringBuffer names = new StringBuffer();
            BigDecimal sumInsFee = BigDecimal.ZERO;
            passengerList.forEach(passenger->{
                names.append(passenger.getPsgName().concat(","));
                if (passenger.getSumInsMoney() != null){
                    sumInsFee.add(passenger.getSumInsMoney());
                }
            });
            cnvTrainOrderDO.setPassenger(names.substring(0,names.length()-1));
            cnvTrainOrderDO.setOAUserCode(passengerList.get(0).getOAUserCode());
            cnvTrainOrderDO.setSumInsMoney(sumInsFee);
        }
    }

    private void convertFromBriTrainOrder(BriTrainOrder briTrainOrder, CnvTrainOrderDO cnvTrainOrderDO) {
        if (briTrainOrder != null) {
            cnvTrainOrderDO.setOrderNo(briTrainOrder.getOrderNo());
            cnvTrainOrderDO.setUserId(briTrainOrder.getUserId());
            cnvTrainOrderDO.setTenant(briTrainOrder.getTenant());
            cnvTrainOrderDO.setPublicOrPriveate(briTrainOrder.getPublicOrPriveate());
            cnvTrainOrderDO.setIsDomc(briTrainOrder.getIsDomc());
            cnvTrainOrderDO.setPreiumReason(briTrainOrder.getPreiumReason());
            cnvTrainOrderDO.setPreiumDetail(briTrainOrder.getPreiumDetail());
            cnvTrainOrderDO.setStatusType(briTrainOrder.getStatusType());
            cnvTrainOrderDO.setSavePrice(briTrainOrder.getSavePrice());
            cnvTrainOrderDO.setCreateBy(briTrainOrder.getCreateBy());
            cnvTrainOrderDO.setOrderTime(briTrainOrder.getOrderTime());
            cnvTrainOrderDO.setPaymentPrice(briTrainOrder.getPaymentPrice());
            cnvTrainOrderDO.setLinkName(briTrainOrder.getLinkName());
            cnvTrainOrderDO.setLinkPhone(briTrainOrder.getLinkPhone());
            cnvTrainOrderDO.setRefundPrice(briTrainOrder.getRefundPrice());
            cnvTrainOrderDO.setTpPrice(briTrainOrder.getTpPrice());
            cnvTrainOrderDO.setSumCounterFee(briTrainOrder.getSumCounterFee());
            cnvTrainOrderDO.setCarrierSumFee(briTrainOrder.getCarrierSumFee());
            cnvTrainOrderDO.setPaymentType(briTrainOrder.getPaymentType());
            cnvTrainOrderDO.setFromType(briTrainOrder.getFromType());
            cnvTrainOrderDO.setPaperTicketFee(briTrainOrder.getPaperTicketFee());
            cnvTrainOrderDO.setTrainOrderNo(briTrainOrder.getTrainOrderNo());
            cnvTrainOrderDO.setPayType(briTrainOrder.getPayType());
            cnvTrainOrderDO.setOrderType(briTrainOrder.getOrderType());
            cnvTrainOrderDO.setBxState(briTrainOrder.getBxState());
            cnvTrainOrderDO.setTicketsNum(briTrainOrder.getTicketsNum());
            cnvTrainOrderDO.setAuthStatus(briTrainOrder.getAuthStatus());
            cnvTrainOrderDO.setCurrency(briTrainOrder.getCurrency());
            cnvTrainOrderDO.setPreOrderMode(briTrainOrder.getPreOrderMode());
            cnvTrainOrderDO.setAllowPayDate(briTrainOrder.getAllowPayDate());
            cnvTrainOrderDO.setParentOrderNo(briTrainOrder.getParentOrderNo());
            cnvTrainOrderDO.setNote(briTrainOrder.getNote());
            cnvTrainOrderDO.setRelateOtherID(briTrainOrder.getRelateOtherID());
            cnvTrainOrderDO.setRelateYBZID(briTrainOrder.getRelateYBZID());
            cnvTrainOrderDO.setCategory(briTrainOrder.getCategory());
            cnvTrainOrderDO.setId(briTrainOrder.getId());
        }
    }

    @Override
    public List<BriTrainOrder> getOrdersByRelateYBZId(List<String> ybzIds)
    {
        if(ybzIds!=null&&ybzIds.size()>0) {
            return briTrainOrderMapper.getTrainOrdersByRelateYBZIds(ybzIds);
        }
        else
        {
            return  new ArrayList<BriTrainOrder>();
        }
    }

    @Override
    public void updateIsNoteByOrderId(int orderId) {
        Map params=new HashMap();
        params.put("id",orderId);
        briTrainOrderMapper.updateIsNoteByOrderId(params);
    }

    @Override
    public List<BriTrainOrder> getOrdersByTimeRange(String tenantId, Date begin, Date end) {
        return briTrainOrderMapper.getOrdersByTimeRange(tenantId, begin, end);
    }

    /**
     * 查询火车票订单详情
     * @param params
     * @return
     */
    @Override
    public JSONObject getTrainOrderJson(JSONObject params) {
        return null;
    }

    @Override
    public BriTrainOrder getTrainOrderJson(String tenant, String orderNo) {
        Wrapper<BriTrainOrder> wrapper = new EntityWrapper<>();
        wrapper.eq("tenant", tenant);
        wrapper.eq("order_no", orderNo);
        List<BriTrainOrder> briTrainOrders = briTrainOrderMapper.selectList(wrapper);
        if (briTrainOrders.size() > 0){
            return briTrainOrders.get(0);
        }
        return null;
    }

    @Override
    public CnvTrainOrderDO getBriTrainOrderByOrderNo(String orderNo) {
        CnvTrainOrderDO cnvTrainOrderDO = new CnvTrainOrderDO();
        BriTrainOrder briTrainOrder = briTrainOrderMapper.getBriTrainOrderByOrderNo(orderNo);
        List<BriTrainTicket> briTrainTickets = briTrainTicketService.getBriTrainTicketByOrderNo(orderNo);
        List<BriTrainPassenger> briTrainPassengers = briTrainPassengerService.getBriTrainPassenger(orderNo);
        if (briTrainOrder != null && briTrainTickets != null && briTrainPassengers != null){
            convertToCnvTrainOrderDO(cnvTrainOrderDO, briTrainOrder, briTrainTickets, briTrainPassengers);
        }
        return cnvTrainOrderDO;
    }

    @Override
    public List<CnvTrainOrderDO> getOrderLikeOrderNo(String orderNo, String fromType, String tenant){
        List<CnvTrainOrderDO> list = new ArrayList<>();

        if ("clyh".equals(fromType)){
            Wrapper<BriTrainOrder> wrapper = new EntityWrapper<>();
            wrapper.eq(BriTrainOrder.TENANT, tenant);
            wrapper.like("order_no", orderNo, SqlLike.RIGHT);
            List<BriTrainOrder> briTrainOrderList = this.selectList(wrapper);
            for (BriTrainOrder briTrainOrder : briTrainOrderList) {
                String briTrainOrderNo = briTrainOrder.getOrderNo();
                List<BriTrainTicket> briTrainTickets = briTrainTicketService.getBriTrainTicketByOrderNo(briTrainOrderNo);
                List<BriTrainPassenger> briTrainPassengers = briTrainPassengerService.getBriTrainPassenger(briTrainOrderNo);
                CnvTrainOrderDO cnvTrainOrderDO = new CnvTrainOrderDO();
                if (briTrainOrder != null && briTrainTickets != null && briTrainPassengers != null){
                    convertToCnvTrainOrderDO(cnvTrainOrderDO, briTrainOrder, briTrainTickets, briTrainPassengers);
                }
                list.add(cnvTrainOrderDO);
            }
        }else {
            CnvTrainOrderDO cnvTrainOrderDO = getBriTrainOrderByOrderNo(orderNo);
            list.add(cnvTrainOrderDO);
        }

        return list;
    }
    private List<BriTrainOrder> getOrderLikeOrderNoV2(String orderNo, String fromType, String tenant){
        List<BriTrainOrder> list = new ArrayList<>();

        if ("clyh".equals(fromType)){
            Wrapper<BriTrainOrder> wrapper = new EntityWrapper<>();
            wrapper.eq(BriTrainOrder.TENANT, tenant);
            wrapper.like("order_no", orderNo, SqlLike.RIGHT);
            List<BriTrainOrder> briTrainOrderList = this.selectList(wrapper);
            for (BriTrainOrder briTrainOrder : briTrainOrderList) {
                String briTrainOrderNo = briTrainOrder.getOrderNo();
                List<BriTrainTicket> briTrainTickets = briTrainTicketService.getBriTrainTicketByOrderNo(briTrainOrderNo);
                List<BriTrainPassenger> briTrainPassengers = briTrainPassengerService.getBriTrainPassenger(briTrainOrderNo);
                if (briTrainOrder != null && briTrainTickets != null && briTrainPassengers != null){
                    list.add(briTrainOrder);
                }
            }
        }else {
            BriTrainOrder briTrainOrder = briTrainOrderMapper.getBriTrainOrderByOrderNo(orderNo);
            if (briTrainOrder != null) {
                list.add(briTrainOrder);
            }
        }

        return list;
    }

    @Override
    public List<CnvTrainOrderDO> getRelationOrders(String orderNo, String parentNo, String fromType, String tenant) {
        HashSet<String> noSet = new HashSet<>();
        List<CnvTrainOrderDO> orderList = new ArrayList<>();
        boolean isClyh = "clyh".equals(fromType);
        boolean hasPsgId = orderNo.split("_").length > 1;
        String passengerId = isClyh && hasPsgId ? orderNo.split("_")[1] : "";
        //查询单是否是其他订单的原单
        List<BriTrainOrder> tgBriTrainOrders = queryLowerOrders(orderNo, isClyh, tenant,fromType);
        for (BriTrainOrder tgBriTrainOrder : tgBriTrainOrders) {
            String tgOrderNo = tgBriTrainOrder.getOrderNo();
            // 其退改单的出行人与其订单的出行人身份证一致, passengerId可能为空
            if (isClyh && hasPsgId  && !passengerId.equals(tgOrderNo.split("_")[1])){
                continue;
            }
            noSet.add(tgOrderNo);
            fillAndConvert(tgBriTrainOrder, orderList);

            //这个单据可能是改签单，查询一下这个单据是否有退单
            List<BriTrainOrder> tggBriTrainOrderList = queryLowerOrders(tgOrderNo, isClyh, tenant,fromType);
            for (BriTrainOrder tggBriTrainOrder : tggBriTrainOrderList) {
                String tggOrderNo = tggBriTrainOrder.getOrderNo();
                // 其退改单的出行人与其订单的出行人身份证一致
                if (isClyh && hasPsgId && !passengerId.equals(tggOrderNo.split("_")[1])){
                    continue;
                }
                noSet.add(tggOrderNo);
                fillAndConvert(tggBriTrainOrder, orderList);

                //这个单据仍然可能是改签单，查询是否有下游单据, 是否有退单
                List<BriTrainOrder> tBriTrainOrderList = queryLowerOrders(tggOrderNo, isClyh, tenant,fromType);
                for (BriTrainOrder tBriTrainOrder : tBriTrainOrderList) {
                    String tOrderNo = tBriTrainOrder.getOrderNo();
                    // 其退改单的出行人与其订单的出行人身份证一致
                    if (isClyh && hasPsgId && !passengerId.equals(tOrderNo.split("_")[1])){
                        continue;
                    }
                    noSet.add(tOrderNo);
                    fillAndConvert(tBriTrainOrder, orderList);
                }
            }
        }

        //查询是否有原单
        if (StringUtil.isNotEmpty(parentNo) && (!orderNo.equals(parentNo) && !orderNo.split("_")[0].equals(parentNo))){
            //查询是否有上游单据
            List<CnvTrainOrderDO> cnvOrderList = this.getOrderLikeOrderNo(parentNo, fromType, tenant);
            for (CnvTrainOrderDO cnvTrainOrderDO : cnvOrderList) {
                String cnvOrderNo = cnvTrainOrderDO.getOrderNo();
                if (StringUtil.isEmpty(cnvOrderNo) || (isClyh && hasPsgId  && !passengerId.equals(cnvOrderNo.split("_")[1])) ){
                    continue;
                }
                noSet.add(cnvOrderNo);
                orderList.add(cnvTrainOrderDO);

                //该原单可能是改签单，查询上游单据,查询是否还有原订单
                String gParentNo = cnvTrainOrderDO.getParentOrderNo();
                if (StringUtil.isNotEmpty(gParentNo) && !cnvOrderNo.equals(gParentNo) && !cnvOrderNo.split("_")[0].equals(gParentNo)){
                    List<CnvTrainOrderDO> ogCnvOrderList = this.getOrderLikeOrderNo(gParentNo, fromType, tenant);
                    for (CnvTrainOrderDO ogCnvOrderDO : ogCnvOrderList) {
                        String ogOrderNo = ogCnvOrderDO.getOrderNo();
                        if (StringUtil.isEmpty(ogOrderNo) || (isClyh && hasPsgId  && !passengerId.equals(ogOrderNo.split("_")[1])) ){
                            continue;
                        }
                        noSet.add(ogOrderNo);
                        orderList.add(ogCnvOrderDO);

                        //该原单仍然可能是改签单，查询是否还有上游单据,查询初始单据
                        String oParentNo = ogCnvOrderDO.getParentOrderNo();
                        if (StringUtil.isNotEmpty(oParentNo) && !ogOrderNo.equals(oParentNo) && !ogOrderNo.split("_")[0].equals(oParentNo)){
                            List<CnvTrainOrderDO> oCnvOrderList = this.getOrderLikeOrderNo(oParentNo, fromType, tenant);
                            for (CnvTrainOrderDO oCnvOrderDO : oCnvOrderList) {
                                String oCnvOrderNo = oCnvOrderDO.getOrderNo();
                                if (StringUtil.isEmpty(oCnvOrderNo) || (isClyh && hasPsgId  && !passengerId.equals(oCnvOrderNo.split("_")[1])) ){
                                    continue;
                                }
                                noSet.add(oCnvOrderNo);
                                orderList.add(oCnvOrderDO);
                            }
                        }else {
                            // 关联关系可能：退改单与原单关联不是顺序的，退改单的原单号都是原单
                            List<BriTrainOrder> sameLevelOrderList = queryLowerOrders(ogOrderNo, isClyh, tenant,fromType);
                            if (sameLevelOrderList != null){
                                for (BriTrainOrder sLOrder : sameLevelOrderList) {
                                    String slOrderNo = sLOrder.getOrderNo();
                                    if (noSet.contains(slOrderNo) || StringUtil.isEmpty(slOrderNo) || (isClyh && hasPsgId  && !passengerId.equals(slOrderNo.split("_")[1])) || slOrderNo.equals(orderNo)){
                                        continue;
                                    }
                                    noSet.add(slOrderNo);
                                    fillAndConvert(sLOrder, orderList);
                                    List<BriTrainOrder> briTrainOrders = queryLowerOrders(slOrderNo, isClyh, tenant,fromType);
                                    for (BriTrainOrder briTrainOrder : briTrainOrders) {
                                        if (!noSet.contains(briTrainOrder.getOrderNo())) {
                                            fillAndConvert(briTrainOrder, orderList);

                                        }

                                    }
                                }
                            }
                        }

                    }
                }else {
                    // 关联关系可能：退改单与原单关联不是顺序的，退改单的原单号都是原单
                    List<BriTrainOrder> sameLevelOrderList = queryLowerOrders(cnvOrderNo, isClyh, tenant,fromType);
                    if (sameLevelOrderList != null){
                        for (BriTrainOrder sLOrder : sameLevelOrderList) {
                            String slOrderNo = sLOrder.getOrderNo();
                            if (StringUtil.isEmpty(slOrderNo) || (isClyh && hasPsgId  && !passengerId.equals(slOrderNo.split("_")[1])) || slOrderNo.equals(orderNo)){
                                continue;
                            }
                            noSet.add(slOrderNo);
                            fillAndConvert(sLOrder, orderList);
                            List<BriTrainOrder> briTrainOrders = queryLowerOrders(slOrderNo, isClyh, tenant,fromType);
                            for (BriTrainOrder briTrainOrder : briTrainOrders) {
                                if (!noSet.contains(briTrainOrder.getOrderNo())) {
                                    fillAndConvert(briTrainOrder, orderList);

                                }

                            }
                        }
                    }
                }
            }
        }
        orderList = distinct(orderList, orderNo);
        return orderList;
    }

    @Override
    public List<BriTrainOrder> getRelationOrdersV2(String orderNo, String parentNo, String fromType, String tenant) {
        HashSet<String> noSet = new HashSet<>();
        List<BriTrainOrder> orderList = new ArrayList<>();
        boolean isClyh = "clyh".equals(fromType);
        boolean hasPsgId = orderNo.split("_").length > 1;
        String passengerId = isClyh && hasPsgId ? orderNo.split("_")[1] : "";
        //查询单是否是其他订单的原单
        List<BriTrainOrder> tgBriTrainOrders = queryLowerOrders(orderNo, isClyh, tenant,fromType);
        for (BriTrainOrder tgBriTrainOrder : tgBriTrainOrders) {
            String tgOrderNo = tgBriTrainOrder.getOrderNo();
            // 其退改单的出行人与其订单的出行人身份证一致, passengerId可能为空
            if (isClyh && hasPsgId  && !passengerId.equals(tgOrderNo.split("_")[1])){
                continue;
            }
            noSet.add(tgOrderNo);
            orderList.add(tgBriTrainOrder);

            //这个单据可能是改签单，查询一下这个单据是否有退单
            List<BriTrainOrder> tggBriTrainOrderList = queryLowerOrders(tgOrderNo, isClyh, tenant,fromType);
            for (BriTrainOrder tggBriTrainOrder : tggBriTrainOrderList) {
                String tggOrderNo = tggBriTrainOrder.getOrderNo();
                // 其退改单的出行人与其订单的出行人身份证一致
                if (isClyh && hasPsgId && !passengerId.equals(tggOrderNo.split("_")[1])){
                    continue;
                }
                noSet.add(tggOrderNo);
                orderList.add(tggBriTrainOrder);

                //这个单据仍然可能是改签单，查询是否有下游单据, 是否有退单
                List<BriTrainOrder> tBriTrainOrderList = queryLowerOrders(tgOrderNo, isClyh, tenant,fromType);
                if (!CollectionUtils.isEmpty(tBriTrainOrderList)) {
                    for (BriTrainOrder tBriTrainOrder : tBriTrainOrderList) {
                        String tOrderNo = tBriTrainOrder.getOrderNo();
                        // 其退改单的出行人与其订单的出行人身份证一致
                        if (isClyh && hasPsgId && !passengerId.equals(tOrderNo.split("_")[1])){
                            continue;
                        }
                        noSet.add(tOrderNo);
                        orderList.add(tBriTrainOrder);
                    }
                }
            }
        }
        //查询是否有原单
        if (StringUtil.isNotEmpty(parentNo) && (!orderNo.equals(parentNo) && !orderNo.split("_")[0].equals(parentNo))){
            //查询是否有上游单据
            List<BriTrainOrder> cnvOrderList = this.getOrderLikeOrderNoV2(parentNo, fromType, tenant);
            for (BriTrainOrder cnvTrainOrderDO : cnvOrderList) {
                String cnvOrderNo = cnvTrainOrderDO.getOrderNo();
                if (StringUtil.isEmpty(cnvOrderNo) || (isClyh && hasPsgId  && !passengerId.equals(cnvOrderNo.split("_")[1])) ){
                    continue;
                }
                noSet.add(cnvOrderNo);

                orderList.add(cnvTrainOrderDO);

                //该原单可能是改签单，查询上游单据,查询是否还有原订单
                String gParentNo = cnvTrainOrderDO.getParentOrderNo();
                if (StringUtil.isNotEmpty(gParentNo) && !cnvOrderNo.equals(gParentNo) && !cnvOrderNo.split("_")[0].equals(gParentNo)){
                    List<BriTrainOrder> ogCnvOrderList = this.getOrderLikeOrderNoV2(gParentNo, fromType, tenant);
                    for (BriTrainOrder ogCnvOrderDO : ogCnvOrderList) {
                        String ogOrderNo = ogCnvOrderDO.getOrderNo();
                        if (StringUtil.isEmpty(ogOrderNo) || (isClyh && hasPsgId  && !passengerId.equals(ogOrderNo.split("_")[1])) ){
                            continue;
                        }
                        noSet.add(ogOrderNo);

                        orderList.add(ogCnvOrderDO);

                        //该原单仍然可能是改签单，查询是否还有上游单据,查询初始单据
                        String oParentNo = ogCnvOrderDO.getParentOrderNo();
                        if (StringUtil.isNotEmpty(oParentNo) && !ogOrderNo.equals(oParentNo) && !ogOrderNo.split("_")[0].equals(oParentNo)){
                            List<BriTrainOrder> oCnvOrderList = this.getOrderLikeOrderNoV2(oParentNo, fromType, tenant);
                            for (BriTrainOrder oCnvOrderDO : oCnvOrderList) {
                                String oCnvOrderNo = oCnvOrderDO.getOrderNo();
                                if (StringUtil.isEmpty(oCnvOrderNo) || (isClyh && hasPsgId  && !passengerId.equals(oCnvOrderNo.split("_")[1])) ){
                                    continue;
                                }
                                noSet.add(oCnvOrderNo);

                                orderList.add(oCnvOrderDO);
                            }
                        }else {
                            // 关联关系可能：退改单与原单关联不是顺序的，退改单的原单号都是原单
                            List<BriTrainOrder> sameLevelOrderList = queryLowerOrders(ogOrderNo, isClyh, tenant,fromType);
                            if (sameLevelOrderList != null) {
                                for (BriTrainOrder sLOrder : sameLevelOrderList) {
                                    String slOrderNo = sLOrder.getOrderNo();
                                    if (noSet.contains(slOrderNo) || StringUtil.isEmpty(slOrderNo) || (isClyh && hasPsgId && !passengerId.equals(slOrderNo.split("_")[1])) || slOrderNo.equals(orderNo)) {
                                        continue;
                                    }
                                    noSet.add(slOrderNo);
                                    orderList.add(sLOrder);
                                    List<BriTrainOrder> briTrainOrders = queryLowerOrders(slOrderNo, isClyh, tenant,fromType);
                                    for (BriTrainOrder briTrainOrder : briTrainOrders) {
                                        if (!noSet.contains(briTrainOrder.getOrderNo())) {
                                            orderList.add(briTrainOrder);
                                        }

                                    }
                                }
                            }
                        }

                    }
                }else {
                    // 关联关系可能：退改单与原单关联不是顺序的，退改单的原单号都是原单
                    List<BriTrainOrder> sameLevelOrderList = queryLowerOrders(cnvOrderNo, isClyh, tenant,fromType);
                    if (sameLevelOrderList != null){
                        for (BriTrainOrder sLOrder : sameLevelOrderList) {
                            String slOrderNo = sLOrder.getOrderNo();
                            if (StringUtil.isEmpty(slOrderNo) || (isClyh && hasPsgId  && !passengerId.equals(slOrderNo.split("_")[1])) || slOrderNo.equals(orderNo)){
                                continue;
                            }
                            noSet.add(slOrderNo);

                            orderList.add(sLOrder);
                            List<BriTrainOrder> briTrainOrders = queryLowerOrders(slOrderNo, isClyh, tenant,fromType);
                            for (BriTrainOrder briTrainOrder : briTrainOrders) {
                                if (!noSet.contains(briTrainOrder.getOrderNo())) {
                                    orderList.add(briTrainOrder);
                                }

                            }
                        }
                    }
                }
            }
        }
        orderList = distinctV2(orderList,orderNo);
        return orderList;
    }

    @Override
    public JSONArray getTrainOrders(String userId, String bxState, String beginDate, String endDate, String tenant, Map<String, List<Map<String, String>>> canBeSeen) {
        List<BriTrainOrder> briTrainOrders = this.getTrainOrdersByBxState(userId, bxState, beginDate, endDate, tenant, canBeSeen);
        return getOrdersDetails(briTrainOrders, true);
    }

    @Override
    public JSONArray getTrainOrders(String tenant, String orderNo) {
        JSONArray result = new JSONArray();
        Wrapper<BriTrainOrder> wrapper = new EntityWrapper<>();
        wrapper.eq(BriTrainOrder.TENANT, tenant);
        wrapper.eq(BriTrainOrder.ORDER_NO, orderNo);
        BriTrainOrder briTrainOrder = this.selectOne(wrapper);
        List<BriTrainOrder> list = new ArrayList<>();
        if (briTrainOrder != null){
            List<BriTrainOrder> relationOrdersList = getRelationOrdersV2(orderNo, briTrainOrder.getParentOrderNo(), briTrainOrder.getFromType(), tenant);
            list.add(briTrainOrder);
            list.addAll(relationOrdersList);
            result.addAll(getOrdersDetails(list, false));
        }
        return result;
    }

    private JSONArray getOrdersDetails(List<BriTrainOrder> briTrainOrders, Boolean isFilter){
        JSONArray trainOrderArr = new JSONArray();

        Iterator<BriTrainOrder> iterator = briTrainOrders.iterator();
        while (iterator.hasNext()) {
            BriTrainOrder briTrainOrder = iterator.next();
            String orderNo = briTrainOrder.getOrderNo();
            JSONObject orderJSON = objToJSONObject(briTrainOrder);
            //火车票乘客信息（BriTrainPassenger）
            List<BriTrainPassenger> passengerList = briTrainPassengerService.getBriTrainPassenger(orderNo);
            JSONArray passengerArr = new JSONArray();
            //火车票票据信息（BriTrainTicket）
            boolean hasTraveled = false;
            for (BriTrainPassenger passenger : passengerList) {
                List<BriTrainTicket> ticketList = briTrainTicketService.getBriTrainTicketByOrderNoAndCardNo(orderNo, passenger.getCardNo());
                if (ticketList != null) {
                    for (BriTrainTicket briTrainTicket : ticketList) {
                        if (briTrainTicket.getToDate() == null || new Date().before(briTrainTicket.getToDate())) {
                            // 未出行
                            hasTraveled = true;
                            break;
                        }
                    }
                }

                JSONArray ticketArr = listToJSONArray(ticketList);
                JSONObject passengerJson = objToJSONObject(passenger);
                passengerJson.put("trainTickets", ticketArr);
                passengerArr.add(passengerJson);
            }
            // 未出行
            if (hasTraveled && isFilter){
                iterator.remove();
                continue;
            }

            orderJSON.put("trainPassengers", passengerArr);

            //火车票支付信息（trainPayments）
            Wrapper<BriTrainPayment> wrapper = new EntityWrapper<>();
            wrapper.eq("order_no", orderNo);
            List<BriTrainPayment> paymentList = briTrainPaymentService.selectList(wrapper);
            JSONArray paymentArr = listToJSONArray(paymentList);
            orderJSON.put("trainPayments", paymentArr);
            //发票信息
            List<InvoiceRelationship> relationshipList = relationshipService.getRelationshipsByOrderNo(orderNo);
            JSONArray relationArr = listToJSONArray(relationshipList);
            orderJSON.put("invoices", relationArr);

            trainOrderArr.add(orderJSON);
        }
        return trainOrderArr;
    }

    @Override
    public List<BriTrainOrder> getTrainOrdersByBxState(String userId, String bxState, String beginDate, String endDate, String tenant, Map<String, List<Map<String, String>>> canBeSeen){
        return briTrainOrderMapper.getOrdersByBxState(userId, bxState, beginDate, endDate, tenant, canBeSeen);
    }
    /**
     * 将对象转成JSONObject
     * @param object
     * @return
     */
    private JSONObject objToJSONObject(Object object){
        String jsonString = JSONObject.toJSONString(object);
        return JSONObject.parseObject(jsonString);
    }

    /**
     * 将list转成JSONArray
     * @param list
     * @return
     */
    private JSONArray listToJSONArray(List list){
        String jsonString = JSONArray.toJSONString(list);
        return JSONArray.parseArray(jsonString);
    }

    private List<BriTrainOrder> queryLowerOrders(String orderNo, boolean isClyh, String tenant,String fromType) {
        String[] orderSplilt = orderNo.split("_");
        //查看该订单是否是其他订单的原单
        Wrapper<BriTrainOrder> wrapper = new EntityWrapper<>();
        wrapper.eq(BriTrainOrder.TENANT, tenant);
        if (isClyh){
            wrapper.like("parent_order_no", orderSplilt[0], SqlLike.RIGHT);
        }else {
            wrapper.eq("parent_order_no", orderNo);
        }
        List<BriTrainOrder> briTrainOrders = this.selectList(wrapper);
        //携程大客户退改签 和 出票 orderNo相同，没有用parent_order_no关联
        if (ChannelEnum.CTRIPBC.getName().equalsIgnoreCase(fromType)) {
            wrapper = new EntityWrapper<>();
            wrapper.eq(BriFlightOrder.TENANT, tenant);
            wrapper.like("order_no", orderSplilt[0], SqlLike.RIGHT);
            briTrainOrders = this.selectList(wrapper);
        }
        List<BriTrainOrder> rsList = new ArrayList<>();
        for (BriTrainOrder briTrainOrder : briTrainOrders) {
            if (orderNo.equals(briTrainOrder.getOrderNo())){
                continue;
            }
            rsList.add(briTrainOrder);
        }
        return rsList;
    }

    private void fillAndConvert(BriTrainOrder briTrainOrder, List<CnvTrainOrderDO> orderList){
        CnvTrainOrderDO cnvTrainOrderDO = new CnvTrainOrderDO();
        List<BriTrainTicket> briTrainTickets = briTrainTicketService.getBriTrainTicketByOrderNo(briTrainOrder.getOrderNo());
        List<BriTrainPassenger> briTrainPassengers = briTrainPassengerService.getBriTrainPassenger(briTrainOrder.getOrderNo());
        convertToCnvTrainOrderDO(cnvTrainOrderDO, briTrainOrder, briTrainTickets, briTrainPassengers);
        orderList.add(cnvTrainOrderDO);
    }

    private void convertToCnvTrainOrderDO(CnvTrainOrderDO cnvTrainOrderDO, BriTrainOrder briTrainOrder, List<BriTrainTicket> briTrainTickets, List<BriTrainPassenger> briTrainPassengers) {
        convertFromBriTrainOrder(briTrainOrder, cnvTrainOrderDO);
        convertFromBriTrainPassengers(cnvTrainOrderDO, briTrainPassengers);
        convertFromBriTrainTicket(cnvTrainOrderDO, briTrainTickets);
    }

    private void convertFromBriTrainTicket(CnvTrainOrderDO cnvTrainOrderDO, List<BriTrainTicket> briTrainTickets) {
        if (!CollectionUtils.isEmpty(briTrainTickets)) {
            if (1 == briTrainTickets.size()) {
                BriTrainTicket briTrainTicket = briTrainTickets.get(0);
                cnvTrainOrderDO.setTktPrice(briTrainTicket.getTktPrice());
                cnvTrainOrderDO.setTrainCode(briTrainTicket.getTrainCode());
                cnvTrainOrderDO.setTrainCodeName(briTrainTicket.getTrainCodeName());
                cnvTrainOrderDO.setFromStation(briTrainTicket.getFromStation());
                cnvTrainOrderDO.setToStation(briTrainTicket.getToStation());
                cnvTrainOrderDO.setTrainDate(briTrainTicket.getTrainDate());
                cnvTrainOrderDO.setFromTime(DateUtils.dateToTime(briTrainTicket.getFromTime()));
                cnvTrainOrderDO.setToDate(briTrainTicket.getToDate());
                cnvTrainOrderDO.setToTime(DateUtils.dateToTime(briTrainTicket.getToTime()));
                cnvTrainOrderDO.setSeatType(briTrainTicket.getSeatType());
                cnvTrainOrderDO.setTunTime(briTrainTicket.getTunTime());
                cnvTrainOrderDO.setTrainBox(briTrainTicket.getTrainBox());
                cnvTrainOrderDO.setSeatNo(briTrainTicket.getSeatNo());
                cnvTrainOrderDO.setCounterFee(briTrainTicket.getCounterFee());
                cnvTrainOrderDO.setSendTicketFee(briTrainTicket.getSendTicketFee());
            } else if (briTrainTickets.size() > 1) {
                Collections.sort(briTrainTickets);
                BriTrainTicket briTrainTicketFirst = briTrainTickets.get(0);
                BriTrainTicket briTrainTicketLast = briTrainTickets.get(briTrainTickets.size() - 1);
                cnvTrainOrderDO.setTktPrice(briTrainTicketFirst.getTktPrice());
                cnvTrainOrderDO.setTrainCode(briTrainTicketFirst.getTrainCode());
                cnvTrainOrderDO.setTrainCodeName(briTrainTicketFirst.getTrainCodeName());
                cnvTrainOrderDO.setFromStation(briTrainTicketFirst.getFromStation());
                cnvTrainOrderDO.setToStation(briTrainTicketLast.getToStation());
                cnvTrainOrderDO.setTrainDate(briTrainTicketFirst.getTrainDate());
                cnvTrainOrderDO.setFromTime(DateUtils.dateToTime(briTrainTicketFirst.getFromTime()));
                cnvTrainOrderDO.setToDate(briTrainTicketLast.getToDate());
                cnvTrainOrderDO.setToTime(DateUtils.dateToTime(briTrainTicketLast.getToTime()));
                cnvTrainOrderDO.setSeatType(briTrainTicketFirst.getSeatType());
                cnvTrainOrderDO.setTunTime(briTrainTicketFirst.getTunTime());
                cnvTrainOrderDO.setTrainBox(briTrainTicketFirst.getTrainBox());
                cnvTrainOrderDO.setSeatNo(briTrainTicketFirst.getSeatNo());
                cnvTrainOrderDO.setCounterFee(briTrainTicketFirst.getCounterFee());
                BigDecimal sendFee = BigDecimal.ZERO;
                BigDecimal carrierChangeFee = BigDecimal.ZERO;
                for (BriTrainTicket briTrainTicket : briTrainTickets) {
                    if (briTrainTicket.getSendTicketFee() != null){
                        sendFee = sendFee.add(briTrainTicket.getSendTicketFee());
                    }
                    if (briTrainTicket.getCarrierChangeFee() != null) {
                        carrierChangeFee = carrierChangeFee.add(briTrainTicket.getCarrierChangeFee());
                    }
                }
                cnvTrainOrderDO.setCarrierChangeFee(carrierChangeFee);
                cnvTrainOrderDO.setSendTicketFee(sendFee);
            }
        }
    }
    private static List<CnvTrainOrderDO> distinct(List<CnvTrainOrderDO> cnvFlightOrderDOList, String orderNo) {
        HashMap<String, CnvTrainOrderDO> map = new HashMap<>();
        for (CnvTrainOrderDO cnvTrainOrderDO : cnvFlightOrderDOList) {
            map.put(cnvTrainOrderDO.getOrderNo(), cnvTrainOrderDO);
        }
        cnvFlightOrderDOList = new ArrayList<CnvTrainOrderDO>();
        for (Map.Entry<String, CnvTrainOrderDO> entry : map.entrySet()) {
            if (!orderNo.equals(entry.getKey())){
                cnvFlightOrderDOList.add(entry.getValue());
            }
        }
        return cnvFlightOrderDOList;
    }
    private static List<BriTrainOrder> distinctV2(List<BriTrainOrder> cnvFlightOrderDOList, String orderNo) {
        HashMap<String, BriTrainOrder> map = new HashMap<>();
        for (BriTrainOrder cnvFlightOrderDO : cnvFlightOrderDOList) {
            map.put(cnvFlightOrderDO.getOrderNo(), cnvFlightOrderDO);
        }
        cnvFlightOrderDOList = new ArrayList<BriTrainOrder>();
        for (Map.Entry<String, BriTrainOrder> entry : map.entrySet()) {
            if (!orderNo.equals(entry.getKey())){
                cnvFlightOrderDOList.add(entry.getValue());
            }
        }
        return cnvFlightOrderDOList;
    }
}
